//题目:
// 给你一个整数数组 nums 。玩家 1 和玩家 2 基于这个数组设计了一个游戏。
// 玩家 1 和玩家 2 轮流进行自己的回合，玩家 1 先手。开始时，两个玩家的初始分值都是 0 。
// 每一回合，玩家从数组的任意一端取一个数字（即，nums[0] 或 nums[nums.length - 1]），取到的数字将会从数组中移除（数组长度减 1 ）。
// 玩家选中的数字将会加到他的得分上。当数组中没有剩余数字可取时，游戏结束。
// 如果玩家 1 能成为赢家，返回 true 。如果两个玩家得分相等，同样认为玩家 1 是游戏的赢家，也返回 true 。
// 你可以假设每个玩家的玩法都会使他的分数最大化。

// 示例 1：
// 输入：nums = [1,5,2]
// 输出：false
// 解释：一开始，玩家 1 可以从 1 和 2 中进行选择。
// 如果他选择 2（或者 1 ），那么玩家 2 可以从 1（或者 2 ）和 5 中进行选择。如果玩家 2 选择了 5 ，那么玩家 1 则只剩下 1（或者 2 ）可选。 
// 所以，玩家 1 的最终分数为 1 + 2 = 3，而玩家 2 为 5 。
// 因此，玩家 1 永远不会成为赢家，返回 false 。

// 示例 2：
// 输入：nums = [1,5,233,7]
// 输出：true
// 解释：玩家 1 一开始选择 1 。然后玩家 2 必须从 5 和 7 中进行选择。无论玩家 2 选择了哪个，玩家 1 都可以选择 233 。
// 最终，玩家 1（234 分）比玩家 2（12 分）获得更多的分数，所以返回 true，表示玩家 1 可以成为赢家。
#include<iostream>
#include<vector>
#include<stack>

using namespace std;
//代码
class Solution {
public:
    bool predictTheWinner(vector<int>& nums) {
        //法一：递归
        // return total(nums, 0, nums.size() - 1, 1) >= 0;

        //法二：动态规划
        int n=nums.size();
        //1.创建dp表————dp[i][j]表示：在nums的[i,j]子数组中，A先手的情况下，A与B的差值
        vector<vector<int>> f(n,vector<int>(n));//A-B的最大差值
        vector<vector<int>> g(n,vector<int>(n));//A-B的最小差值
        //2.初始化————暂无
        //3.填表————动态转移方程:
        for(int i=n-1;i>=0;i--)
        {
            f[i][i]=g[i][i]=nums[i];
            for(int j=i+1;j<n;j++)
            {
                f[i][j]=max(nums[i]-g[i+1][j],nums[j]-g[i][j-1]);
                g[i][j]=max(nums[i]-f[i+1][j],nums[j]-f[i][j-1]);
            }
        }
        //4.确定返回值
        return f[0][n-1]>=0?true:false;
    }

    int total(vector<int>& nums, int start, int end, int turn) {
        if (start == end) {
            return nums[start] * turn;
        }
        int scoreStart = nums[start] * turn + total(nums, start + 1, end, -turn);
        int scoreEnd = nums[end] * turn + total(nums, start, end - 1, -turn);
        return max(scoreStart * turn, scoreEnd * turn) * turn;
    }
};